/* global React */
// Vote — ranked-choice (instant-runoff). Each driver ranks the options; tabulation
// eliminates the lowest first-choice and redistributes until one has a majority.
// Nothing is locked to a fixed slate — drivers can also propose an option.
function VoteScreen() {
  const { Button, Card, Badge, Input } = window.GT7LeagueDesignSystem_258437;
  const D = window.GT7DATA;
  const POLLS = { Feature: D.poll, Sprint: D.sprintPoll };

  const [subject, setSubject] = React.useState('Feature');
  const [optionsBy, setOptionsBy] = React.useState({
    Feature: D.poll.options, Sprint: D.sprintPoll.options,
  });
  const [rankingBy, setRankingBy] = React.useState({
    Feature: D.poll.options.map(o => o.id), Sprint: D.sprintPoll.options.map(o => o.id),
  });
  const [submittedBy, setSubmittedBy] = React.useState({ Feature: false, Sprint: false });
  const [proposal, setProposal] = React.useState('');

  const poll = POLLS[subject];
  const options = optionsBy[subject];
  const ranking = rankingBy[subject];
  const submitted = submittedBy[subject];
  const byId = Object.fromEntries(options.map(o => [o.id, o]));

  const move = (i, dir) => {
    if (submitted) return;
    const j = i + dir;
    if (j < 0 || j >= ranking.length) return;
    setRankingBy(m => {
      const n = [...m[subject]]; [n[i], n[j]] = [n[j], n[i]];
      return { ...m, [subject]: n };
    });
  };
  const submit = () => setSubmittedBy(m => ({ ...m, [subject]: true }));
  const reset = () => setSubmittedBy(m => ({ ...m, [subject]: false }));

  const propose = () => {
    const name = proposal.trim();
    if (!name || submitted) return;
    const id = 'p' + Date.now();
    setOptionsBy(m => ({ ...m, [subject]: [...m[subject], { id, title: name, meta: 'Proposed by you · pending', votes: 0 }] }));
    setRankingBy(m => ({ ...m, [subject]: [...m[subject], id] }));
    setProposal('');
  };

  const result = submitted ? runIRV([...poll.otherBallots, ranking], ranking) : null;
  const bothIn = submittedBy.Feature && submittedBy.Sprint;

  // Auto-feed: when a ballot is submitted, publish its winner so the Round Builder
  // can pre-fill the next round from the vote.
  React.useEffect(() => {
    const store = window.GT7VOTE = window.GT7VOTE || {};
    ['Feature', 'Sprint'].forEach(s => {
      if (!submittedBy[s]) return;
      const p = POLLS[s];
      const r = runIRV([...p.otherBallots, rankingBy[s]], rankingBy[s]);
      const win = p.options.find(o => o.id === r.winner);
      if (win && win.build) store[s.toLowerCase()] = { label: win.title, build: win.build };
    });
    // Auto-flow: write the winners straight onto the next scheduled round (least admin).
    const nr = D.schedule.find(x => x.status === 'next');
    if (nr) {
      if (store.feature) { const b = store.feature.build; nr.track = b.track; nr.featureCar = b.car; nr.laps = b.laps; }
      if (store.sprint) { const b = store.sprint.build; nr.sprint = store.sprint.label + (b.klass !== 'Road' ? ' · BoP on' : ` · ${b.min}–${b.max} PP`); }
      if (store.feature || store.sprint) nr.fromVote = true;
    }
    window.dispatchEvent(new CustomEvent('gt7-vote'));
  }, [submittedBy]); // eslint-disable-line

  return (
    <div style={{ maxWidth: 660, margin: '0 auto' }}>
      <PageTitle eyebrow={`Ranked-choice vote · ${poll.closes}`} title="Vote — Round 6"
        note="Two ballots per round: one for the sprint car pool, one for the feature car & track. Rank each most-to-least preferred; lowest is dropped and its votes flow to the next pick." />

      {/* Subject toggle */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 18, flexWrap: 'wrap', gap: 12 }}>
        <VoteSegmented options={['Feature', 'Sprint']} value={subject} onChange={setSubject}
          done={{ Feature: submittedBy.Feature, Sprint: submittedBy.Sprint }} />
        <span style={{ fontSize: 12.5, color: 'var(--text-faint)' }}>
          {bothIn ? 'Both ballots submitted ✓' : `${(submittedBy.Feature ? 1 : 0) + (submittedBy.Sprint ? 1 : 0)} of 2 ballots submitted`}
        </span>
      </div>

      <div style={{ fontFamily: 'var(--font-display)', fontSize: 13, fontWeight: 600, letterSpacing: '.06em', textTransform: 'uppercase', color: 'var(--text-muted)', marginBottom: 12 }}>{poll.title}</div>

      {!submitted ? (
        <>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {ranking.map((id, i) => (
              <div key={id} style={{
                display: 'flex', alignItems: 'center', gap: 14,
                padding: '12px 14px', background: 'var(--surface-card)',
                border: '1px solid var(--border-subtle)', borderLeft: `3px solid ${rankColor(i)}`,
                borderRadius: 'var(--radius-md)',
              }}>
                <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 22, color: rankColor(i), width: 28, textAlign: 'center', fontVariantNumeric: 'tabular-nums' }}>{i + 1}</span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 16, color: 'var(--text-strong)' }}>{byId[id].title}</div>
                  <div style={{ fontSize: 12.5, color: 'var(--text-faint)' }}>{byId[id].meta}</div>
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                  <ArrowBtn dir="up" disabled={i === 0} onClick={() => move(i, -1)} />
                  <ArrowBtn dir="down" disabled={i === ranking.length - 1} onClick={() => move(i, 1)} />
                </div>
              </div>
            ))}
          </div>

          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 18 }}>
            <span style={{ fontSize: 13, color: 'var(--text-faint)', fontFamily: 'var(--font-mono)' }}>5 of 6 drivers have voted</span>
            <Button variant="data" onClick={submit}>Submit {subject.toLowerCase()} ballot</Button>
          </div>
        </>
      ) : (
        <RunoffResult result={result} byId={byId} onReset={reset} />
      )}

      {/* Propose */}
      {!submitted && (
        <Card style={{ marginTop: 24 }}>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: 12, letterSpacing: '.12em', textTransform: 'uppercase', color: 'var(--text-muted)', marginBottom: 12 }}>Propose a {subject.toLowerCase()} option</div>
          <div style={{ display: 'flex', gap: 10, alignItems: 'flex-end' }}>
            <Input placeholder={subject === 'Sprint' ? 'e.g. American muscle — 580–620 PP' : 'e.g. Suzuka · Mercedes-AMG GT3'} value={proposal} onChange={e => setProposal(e.target.value)} />
            <Button variant="secondary" onClick={propose}>Add</Button>
          </div>
          <p style={{ margin: '10px 0 0', fontSize: 12, color: 'var(--text-faint)' }}>New proposals join this ballot and can be ranked immediately.</p>
        </Card>
      )}
    </div>
  );
}

function VoteSegmented({ options, value, onChange, done }) {
  return (
    <div style={{ display: 'inline-flex', background: 'var(--ink-900)', border: '1px solid var(--border-subtle)', borderRadius: 'var(--radius-sm)', padding: 3, gap: 3 }}>
      {options.map(o => {
        const on = o === value;
        return (
          <button key={o} onClick={() => onChange(o)} style={{
            display: 'inline-flex', alignItems: 'center', gap: 7, padding: '8px 18px', border: 'none', cursor: 'pointer', borderRadius: 'var(--radius-xs)',
            fontFamily: 'var(--font-display)', fontSize: 13, fontWeight: 600, letterSpacing: '.08em', textTransform: 'uppercase',
            background: on ? 'var(--brand)' : 'transparent', color: on ? '#fff' : 'var(--text-faint)', transition: 'background 120ms',
          }}>
            {o}
            <span style={{ width: 7, height: 7, borderRadius: 999, background: done && done[o] ? 'var(--green-500)' : (on ? 'rgba(255,255,255,.4)' : 'var(--ink-600)') }} />
          </button>
        );
      })}
    </div>
  );
}

// ---- Instant-runoff tabulation ----
function runIRV(ballots, candidates) {
  let active = new Set(candidates);
  const rounds = [];
  while (true) {
    const tally = {}; active.forEach(c => (tally[c] = 0));
    ballots.forEach(b => { const top = b.find(c => active.has(c)); if (top != null) tally[top]++; });
    const total = Object.values(tally).reduce((a, x) => a + x, 0);
    const entries = Object.entries(tally).sort((a, b) => b[1] - a[1]);
    if (!entries.length) return { winner: null, rounds };
    const [leader, leadVotes] = entries[0];
    if (leadVotes > total / 2 || active.size <= 1) {
      rounds.push({ tally: { ...tally }, total, majority: true });
      return { winner: leader, rounds };
    }
    const min = Math.min(...Object.values(tally));
    const losers = entries.filter(([, v]) => v === min).map(([c]) => c);
    const eliminated = losers[losers.length - 1];
    rounds.push({ tally: { ...tally }, total, eliminated });
    active.delete(eliminated);
  }
}

function RunoffResult({ result, byId, onReset }) {
  const { Button, Card, Badge } = window.GT7LeagueDesignSystem_258437;
  const winner = result.winner;
  return (
    <div>
      <Card accent="cyan" style={{ marginBottom: 18 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
          <Badge tone="positive" solid>Winner</Badge>
          <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 26, color: 'var(--text-strong)' }}>{byId[winner] ? byId[winner].title : '—'}</span>
        </div>
        <p style={{ margin: '8px 0 0', fontSize: 13, color: 'var(--text-muted)' }}>Decided over {result.rounds.length} runoff round{result.rounds.length > 1 ? 's' : ''} · majority of {result.rounds[0].total} ballots.</p>
      </Card>

      <div style={{ fontFamily: 'var(--font-display)', fontSize: 11, letterSpacing: '.13em', textTransform: 'uppercase', color: 'var(--text-muted)', marginBottom: 12 }}>Runoff rounds</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        {result.rounds.map((rd, ri) => {
          const entries = Object.entries(rd.tally).sort((a, b) => b[1] - a[1]);
          return (
            <Card key={ri} padded>
              <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 10 }}>
                <span style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 13, letterSpacing: '.08em', textTransform: 'uppercase', color: 'var(--text-muted)' }}>Round {ri + 1}</span>
                {rd.majority ? <Badge tone="positive">Majority reached</Badge> : <Badge tone="danger">Drop: {byId[rd.eliminated] ? byId[rd.eliminated].title : rd.eliminated}</Badge>}
              </div>
              {entries.map(([id, v]) => {
                const pct = rd.total ? Math.round((v / rd.total) * 100) : 0;
                const isElim = id === rd.eliminated;
                const isWin = rd.majority && id === result.winner;
                return (
                  <div key={id} style={{ marginBottom: 8, opacity: isElim ? 0.5 : 1 }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, marginBottom: 4 }}>
                      <span style={{ color: 'var(--text-body)', textDecoration: isElim ? 'line-through' : 'none' }}>{byId[id] ? byId[id].title : id}</span>
                      <span style={{ fontFamily: 'var(--font-mono)', color: 'var(--text-faint)' }}>{v} · {pct}%</span>
                    </div>
                    <div style={{ height: 6, background: 'var(--ink-800)', borderRadius: 999, overflow: 'hidden' }}>
                      <div style={{ height: '100%', width: `${pct}%`, background: isWin ? 'var(--positive)' : isElim ? 'var(--caution)' : 'var(--accent)', borderRadius: 999, transition: 'width 300ms' }} />
                    </div>
                  </div>
                );
              })}
            </Card>
          );
        })}
      </div>

      <div style={{ marginTop: 18 }}>
        <Button variant="ghost" onClick={onReset}>Re-rank my ballot</Button>
      </div>
    </div>
  );
}

function rankColor(i) {
  return ['var(--gold-500)', 'var(--accent)', 'var(--ink-400)'][i] || 'var(--ink-600)';
}
function ArrowBtn({ dir, disabled, onClick }) {
  return (
    <button onClick={onClick} disabled={disabled} style={{
      width: 30, height: 22, borderRadius: 'var(--radius-xs)', cursor: disabled ? 'default' : 'pointer',
      background: 'var(--surface-raised)', border: '1px solid var(--border-subtle)',
      color: disabled ? 'var(--ink-600)' : 'var(--text-body)', fontSize: 10, lineHeight: 1,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>{dir === 'up' ? '▲' : '▼'}</button>
  );
}
window.VoteScreen = VoteScreen;
